<?php

/**
 * RHDateTime.php
 */

namespace RHX\Helper;

use Zend\Log\Logger;
use Zend\Log\Writer\Stream;

class RHDateTime {

    private $datetime;
    private $H	 = 0;
    private $MN	 = 0;

    /**
     * Log
     *
     * @var Logger
     */
    private $log = null;

    /**
     * Constructeur
     *
     * @param string $time
     */
    public function __construct($time = 'now') {
	try {
	    $this->datetime = new \DateTime($time, new \DateTimeZone('Europe/Paris'));
//	    $this->log	 = new Logger();
//	    $writer		 = new Stream('module/RHX/logs/log-DateTime-' . date('Y-m-d') . '.txt');
//	    $this->log->addWriter($writer);
//	    $this->log->info("/******/");
	}
	catch (\Exception $ex) {
	    $this->datetime = new \DateTime('now', new \DateTimeZone('Europe/Paris'));
//	    $this->log->warn("La date en paramètre a générer une execption, la date en cours a été retenue");
	}
    }

    /**
     * Affiche la date en cours
     *
     * @return string
     * @throws \RHX\Helper\Exception
     */
    public function __toString() {
	try {
	    return $this->date();
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Ajouter des Jours à la date en Cours
     *
     * @param int $days
     * @throws \RHX\Helper\Exception
     */
    public function addDays($days) {
	try {
	    $interval = date_interval_create_from_date_string($days . ' days');
	    $this->datetime->add($interval);
	    // Deboggage
//	    $this->log->debug("Ajout de Jour de $days, Interval : $interval");
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Soustraire des JOurs à la date en cours
     *
     * @param int $days
     * @throws \RHX\Helper\Exception
     */
    public function subDays($days) {
	try {
	    $interval = date_interval_create_from_date_string($days . ' days');
	    $this->datetime->sub($interval);
	    // Deboggage
//	    $this->log->debug("Soustraction de Jour de $days, Interval : $interval");
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Ajouter des heures à la date en cours
     *
     * @param string $hours
     * @param Boolean $realistic
     * @throws \RHX\Helper\Exception
     */
    public function addHours($hours, $realistic = true) {
	try {
	    $data		 = explode(':', $hours);
	    $h		 = (int) $data[0];
	    $mn		 = (int) $data[1];
	    $interval	 = new \DateInterval('P0D');
	    $interval->h	 = $h;
	    $interval->i	 = $mn;
	    if ($realistic) {
		$this->datetime->add($interval);
		// Deboggage
//		$this->log->debug("Ajout d'Heure Réaliste de $hours, Interval : " . $interval->format('%H:%I'));
	    }
	    else {
		// Deboggage
//		$this->log->debug("Ajout d'Heure Non-Réaliste de $hours, Interval : " . $interval->format('%H:%I'));
		$this->H += $h;
		$this->MN += $mn;
		if ($this->MN >= 60) {
		    $this->H++;
		    $this->MN -= 60;
		}
	    }
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Soustraire des heures à la date en cours
     *
     * @param int $hours
     * @throws \RHX\Helper\Exception
     */
    public function subHours($hours) {
	try {
	    try {
		$data		 = explode(':', $hours);
		$h		 = $data[0];
		$mn		 = $data[1];
		$interval	 = new \DateInterval('P0D');
		$interval->h	 = (int) $h;
		$interval->i	 = (int) $mn;
		$this->datetime->sub($interval);
	    }
	    catch (\Exception $ex) {
		throw $ex;
	    }
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Afficher la date au format MySQL (ISO)
     *
     * @return string
     * @throws \RHX\Helper\Exception
     */
    public function date($format = 'Y-m-d') {
	try {
	    return $this->datetime->format($format);
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Afficher la Date en Français : Lundi, ...
     * @param bool $dayWeek indique l'affichage du jour de la semaine
     * @return string
     * @throws \RHX\Helper\Exception
     */
    public function dateFr($dayWeek = true) {
	try {
	    //$fr = strftime("%A %d %m %Y", $this->datetime->getTimestamp());
	    $jours	 = array('Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi',);
	    $mois	 = array('01'	 => 'Janvier', '02'	 => 'Février', '03'	 => 'Mars', '04'	 => 'Avril', '05'	 => 'Mai', '06'	 => 'Juin',
		'07'	 => 'Juillet', '08'	 => 'Août', '09'	 => 'Septembre', '10'	 => 'Octobre', '11'	 => 'Novembre', '12'	 => 'Décembre');
	    $w	 = strftime("%w", $this->datetime->getTimestamp());
	    $m	 = strftime("%m", $this->datetime->getTimestamp());
	    $d	 = strftime("%d", $this->datetime->getTimestamp());
	    $y	 = strftime("%Y", $this->datetime->getTimestamp());

            if($dayWeek)
                return "{$jours[$w]} $d {$mois[$m]} $y";
            else
                return "$d {$mois[$m]} $y";
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Afficher l'heure
     *
     * @param bool $withseconds
     * @return string
     * @throws \RHX\Helper\Exception
     */
    public function hours($withseconds = false) {
	try {
	    if ($withseconds)
		return $this->datetime->format('H:i:s');
	    else
		return $this->datetime->format('H:i');
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Le Total des heures
     *
     * @return String
     */
    public function totalHours() {
	$totalHeure	 = '';
	$totalMinute	 = '';
	if ($this->H < 10)
	    $totalHeure	 = '0' . $this->H;
	else
	    $totalHeure	 = $this->H;
	if ($this->MN < 10)
	    $totalMinute	 = '0' . $this->MN;
	else
	    $totalMinute	 = $this->MN;

	return $totalHeure . ':' . $totalMinute;
    }

    /**
     * Heure au format HH
     *
     * @return String
     * @throws \RHX\Helper\Exception
     */
    public function getH() {
	try {
	    return $this->datetime->format("H");
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Minute au format MN
     *
     * @return String
     * @throws \RHX\Helper\Exception
     */
    public function getM() {
	try {
	    return $this->datetime->format("i");
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Comparer l'égalité de deux Date
     *
     * @param \RHX\Helper\RHDateTime $date
     * @return bool
     * @throws \RHX\Helper\Exception
     */
    public function isEqual(RHDateTime $date) {
	try {
	    return $this->datetime == $date->datetime;
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Déterminer si la Date en cours est supérieure à la date en paramètre
     *
     * @param \RHX\Helper\RHDateTime $date
     * @return bool
     * @throws \RHX\Helper\Exception
     */
    public function isGT(RHDateTime $date) {
	try {
	    return $this->datetime > $date->datetime;
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Déterminer si la Date en cours est inférieure à la date en paramètre
     *
     * @param \RHX\Helper\RHDateTime $date
     * @return bool
     * @throws \RHX\Helper\Exception
     */
    public function isLT(RHDateTime $date) {
	try {
	    return $this->datetime < $date->datetime;
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Déterminer l'égalité des heures et minutes
     *
     * @param \RHX\Helper\RHDateTime $date
     * @return boolean
     * @throws \RHX\Helper\Exception
     */
    public function isTimeEqual(RHDateTime $date) {
	try {
	    $interval = $this->datetime->diff($date->datetime);
	    if ($interval->h != 0 || $interval->i != 0)
		return false;
	    else
		return true;
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Déterminer si l'heure en cours est Supérieur à l'heure en paramètre
     *
     * @param \RHX\Helper\RHDateTime $date
     * @return boolean
     * @throws \RHX\Helper\Exception
     */
    public function isTimeGT(RHDateTime $date) {
	try {
	    $interval = $this->datetime->diff($date->datetime);
	    //var_dump($interval);
	    if ($interval->invert > 0) {
		// Toutes les valeurs sont négatives
		// Donc l'heure actuelle est supérieur à l'heure en paramètre
		return true;
	    }
	    else {
		// Toutes les valeurs sont positives
		// Donc l'heure actuelle est inférieure ou égale à l'heure en paramètre
		return false;
	    }
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Déterminer si la date en cours est entre les dates en paramètres
     *
     * @param \RHX\Helper\RHDateTime $begin
     * @param \RHX\Helper\RHDateTime $end
     * @return boolean
     */
    public function isBetween(RHDateTime $begin, RHDateTime $end) {
	if ((($this->datetime > $begin->datetime) && ($this->datetime < $end->datetime)) || ($this->datetime == $begin->datetime) || ($this->datetime == $end->datetime)) {
	    return true;
	}
	else {
	    return false;
	}
    }

    /**
     * Déterminer si l'heure en cours est entre les heures en paramètres
     *
     * @param \RHX\Helper\RHDateTime $begin
     * @param \RHX\Helper\RHDateTime $end
     * @return boolean
     */
    public function isTimeBetween(RHDateTime $begin, RHDateTime $end) {
	if ($begin->isTimeEqual($this) || $end->isTimeEqual($this))
	    return true;
	if (!$begin->isTimeGT($this) && $end->isTimeGT($this))
	    return true;
	else
	    return false;
    }

    /**
     * Détermine l'égalité du nom du jour
     *
     * @param type $dayname
     * @return boolean
     */
    public function isDay($dayname = 'lundi') {
	$name	 = $this->dateFr();
	$data	 = explode(' ', $name);
	if (strtolower($data[0]) == strtolower($dayname))
	    return true;
	else
	    return false;
    }

    /**
     * Modifier la date
     *
     * @param type $modification
     * @throws \RHX\Helper\Exception
     */
    public function modify($modification) {
	try {
	    $this->datetime->modify($modification);
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Définir le temps
     *
     * @param string $time
     * @throws \RHX\Helper\Exception
     */
    public function setTime($time = '00:00:00') {
	try {
	    $data	 = explode(':', $time);
	    $hour	 = isset($data[0]) ? (int) $data[0] : 0;
	    $minute	 = isset($data[1]) ? (int) $data[1] : 0;
	    $this->datetime
		    ->setTime($hour, $minute, 0);
	}
	catch (\Exception $ex) {
	    throw $ex;
	}
    }

    /**
     * Effectue une différence d'heure
     *
     * @param string $hour1
     * @param string $hour2
     * @param bool $absolute
     * @return string
     */
    public static function diffHours($hr1, $hr2, $realistic = true, $absolute = true) {
	if ($realistic) {
	    $hour1		 = new \DateTime($hr1);
	    $hour2		 = new \DateTime($hr2);
	    $interval	 = $hour1->diff($hour2, $absolute);
	    $result		 = $interval->format('%H:%I');

	    // Deboggage
//	    $log	 = new Logger();
//	    $writer	 = new Stream('module/RHX/logs/log-DateTime-' . date('Y-m-d') . '.txt');
//	    $log->addWriter($writer);
//	    $log->info("/******/");
//	    $log->debug("Différence d'heure Réaliste entre ($hr1, $hr2) => " . $hour1->format('H:I') . " et " . $hour2->format('H:I') . " = " . $interval->format('%H:%I'));

	    return $result;
	}
	else {
	    // constante
	    $hh	 = 0;
	    $mn	 = 1;
	    $ss	 = 2;
	    $h1	 = explode(':', $hr1);
	    $h2	 = explode(':', $hr2);
	    //var_dump($h1);
	    //var_dump($h2);
	    // ParseInt
	    $h1[$hh] = (isset($h1[$hh])) ? (int) $h1[$hh] : 0;
	    $h1[$mn] = (isset($h1[$mn])) ? (int) $h1[$mn] : 0;
	    $h1[$ss] = (isset($h1[$ss])) ? (int) $h1[$ss] : 0;

	    $h2[$hh] = (isset($h2[$hh])) ? (int) $h2[$hh] : 0;
	    $h2[$mn] = (isset($h2[$mn])) ? (int) $h2[$mn] : 0;
	    $h2[$ss] = (isset($h2[$ss])) ? (int) $h2[$ss] : 0;

	    // Résultat Calcul
	    $h = array(
		$hh	 => 0,
		$mn	 => 0,
	    );

	    // Calcul : On ne fait le calcul des secondes
	    // Teste des Heures : comparaison si h2 > h1
	    if ($h2[$hh] > $h1[$hh]) {
		// SWAP Calcul
		//echo '<pre>Swap Calcul car h2 > h1 en heure</pre>';
		return self::diffHours($hr2, $hr1, false);
	    }
	    else {
		// Test Minute
		if ($h2[$mn] > $h1[$mn]) {
		    // Test Heure1 si égal à zéro
		    if ($h1[$hh] == 0) {
			// SWAP Calcul
			//echo '<pre>Swap Calcul car h1 == 0 et les minutes de h2 > minute de h1</pre>';
			return self::diffHours($hour2, $hour1, false);
		    }
		    else {
			// Heure - 1
			//echo '<pre>heure moins 1</pre>';
			$h1[$hh] --;
			$h1[$mn]+= 60;
		    }
		}
		// Calcul Minute
		$h[$mn]	 = $h1[$mn] - $h2[$mn];
		// Calcul Heure
		$h[$hh]	 = $h1[$hh] - $h2[$hh];
	    }

	    // Traitement des données d'affichage
	    $h[$hh]	 = ((int) $h[$hh] < 10) ? '0' . $h[$hh] : $h[$hh];
	    $h[$mn]	 = ((int) $h[$mn] < 10) ? '0' . $h[$mn] : $h[$mn];

	    // Débogage
//	    $log	 = new Logger();
//	    $writer	 = new Stream('module/RHX/logs/log-DateTime-' . date('Y-m-d') . '.txt');
//	    $log->addWriter($writer);
//	    $log->info("/******/");
//	    $log->debug("Différence d'heure Non-Réaliste entre $hr1 et $hr2 = {$h[$hh]}:{$h[$mn]}");
	    //var_dump($h);
	    return "{$h[$hh]}:{$h[$mn]}";
	}
    }

    /**
     * Transforme une date au format HH:MM en Float
     * 
     * @param string $time
     * @param int $round
     * @return float
     */
    public static function toFloat($time, $round = 2) {
	$data		 = explode(':', $time);
	$heure		 = (int) $data[0];
	$minute		 = (int) $data[1];
	$floatMinute	 = (float) $minute / 60.0;
	$floatHeure	 = (float) $heure;
	$valeur		 = $floatHeure + $floatMinute;

	return round($valeur, $round);
    }

    /**
     * Conversion Float en String Heure HH:MM
     * 
     * @param float $float
     * @return string
     */
    public static function toTime($float) {
	//echo "<pre>Conversion de $float en Temps</pre>";
	$negative	 = false;
	if (is_string($float)) {
	    $float = floatval(str_replace(',', '.', $float));
	    //echo "<pre>$float etait un string</pre>";
	}
	if (!is_numeric($float)) {
	    //echo "<pre>$float n'est pas numerique</pre>";
	    throw new \Exception("Le paramètre fournit n'est pas un Nombre");
	}
	if ($float < 0) {
	    $negative = true;
	}
	$totalMinute	 = $float * 60;
	$minute		 = $totalMinute % 60;
	$heure		 = ($totalMinute - $minute) / 60;
	//echo "<pre>Heure : $heure, Minute : $minute</pre>";

	// Minute en Absolue
	$minute	 = abs($minute);
	$heure	 = abs($heure);
	$minute	 = floatval(number_format($minute, 2));
	$heure	 = floatval(number_format($heure, 0));

	$affHeure	 = ($heure < 10) ? '0' . $heure : $heure;
	$affMinute	 = ($minute < 10) ? '0' . $minute : $minute;

	// Negative ou Positive
	$value = "$affHeure:$affMinute";
	if ($negative) {
	    $value = '-' . $value;
	}
	//echo "<pre>$float en Temps donne $value</pre>";

	return $value;
    }

    /**
     * Retourne l'heure sans les secondes
     *
     * @param string $time
     * @return string
     */
    public static function hourNoSecond($time) {
	$data	 = explode(':', $time);
	$h	 = isset($data[0]) ? $data[0] : '00';
	$mn	 = isset($data[1]) ? $data[1] : '00';

	return "$h:$mn";
    }

    public static function dayName($date = 'now') {
	$date	 = new RHDateTime($date);
	$name	 = $date->dateFr();
	$data	 = explode(' ', $name);

	return strtolower($data[0]);
    }

    /**
     * Fonction de verification si une année est bissextile.
     * 
     * @param integer $year Année (AAAA)
     * @return boolean Vrai ou Faux
     */
    public static function isLeapYear($year) {
	return (cal_days_in_month(CAL_GREGORIAN, 2, $year) === 29) ? true : false;
    }

}

?>
